package com.katze.boot.plugins.security.handle;

import com.katze.boot.plugins.security.domain.RootObject;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * DefaultMethodSecurityExpressionHandler是处理方法安全表达式的默认处理器。
 * 如果你想注册自定义的安全表达式方法，需要创建一个自定义的表达式处理器，继承自DefaultMethodSecurityExpressionHandler，
 * 并重写createSecurityExpressionRoot方法来回调自己的MethodSecurityExpressionOperations实现类
 */
public class AuthorizeExpressionHandler extends DefaultMethodSecurityExpressionHandler {

    @Override
    public EvaluationContext createEvaluationContext(Supplier<Authentication> authentication, MethodInvocation invocation) {
        // 替换为自定义 ROOT OBJECT
        MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(
                createSecurityExpressionRoot(authentication, invocation),
                getSpecificMethod(invocation),
                invocation.getArguments(),
                getParameterNameDiscoverer());
        context.setBeanResolver(getBeanResolver());
        return context;
    }

    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
        return createSecurityExpressionRoot(() -> authentication, invocation);
    }

    private static Method getSpecificMethod(MethodInvocation invocation) {
        return AopUtils.getMostSpecificMethod(invocation.getMethod(), AopProxyUtils.ultimateTargetClass(Objects.requireNonNull(invocation.getThis())));
    }

    //创建自定义 ROOT OBJECT
    private MethodSecurityExpressionOperations createSecurityExpressionRoot(Supplier<Authentication> authentication, MethodInvocation invocation) {
        RootObject root = new RootObject(authentication);
        root.setMethodInvocation(invocation);
        root.setThis(invocation.getThis());
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(getTrustResolver());
        root.setRoleHierarchy(getRoleHierarchy());
        root.setDefaultRolePrefix(getDefaultRolePrefix());
        return root;
    }
}
